import CryptoJS from 'crypto-js'; // 使用 crypto-js 库进行加解密

class CryptoUtils {
    /**
     * 初始化加解密工具
     * @param {string} key - 密钥（字符串）
     * @param {string} iv - 初始化向量（字符串）
     * @param {string} mode - 加密模式，'DES' 或 'AES'
     */
    constructor(key, iv, mode = 'DES') {
        this.mode = mode.toUpperCase(); // 统一转换为大写
        this.key = this._processKey(key); // 处理密钥
        this.iv = this._processIV(iv); // 处理 IV
    }

    /**
     * 处理密钥，确保其长度符合加密算法的要求
     * @param {string} key - 原始密钥（字符串）
     * @returns {CryptoJS.lib.WordArray} - 处理后的密钥
     */
    _processKey(key) {
        const keyBytes = CryptoJS.enc.Utf8.parse(key); // 将密钥转换为字节数组
        if (this.mode === 'DES') {
            // DES 密钥长度必须为 8 字节
            return this._adjustLength(keyBytes, 8);
        } else if (this.mode === 'AES') {
            // AES 密钥长度必须为 16、24 或 32 字节
            // 使用 SHA-256 哈希函数处理密钥，确保其长度为 32 字节
            const hasher = CryptoJS.algo.SHA256.create();
            hasher.update(keyBytes);
            return hasher.finalize();
        } else {
            throw new Error('Unsupported encryption mode');
        }
    }

    /**
     * 处理初始向量，确保其长度符合加密算法的要求
     * @param {string} iv - 原始初始向量（字符串）
     * @returns {CryptoJS.lib.WordArray} - 处理后的 IV
     */
    _processIV(iv) {
        const ivBytes = CryptoJS.enc.Utf8.parse(iv); // 将 IV 转换为字节数组
        if (this.mode === 'DES') {
            // DES IV 长度必须为 8 字节
            return this._adjustLength(ivBytes, 8);
        } else if (this.mode === 'AES') {
            // AES IV 长度必须为 16 字节
            return this._adjustLength(ivBytes, 16);
        } else {
            throw new Error('Unsupported encryption mode');
        }
    }

    /**
     * 调整数据的长度，通过截断或填充的方式
     * @param {CryptoJS.lib.WordArray} data - 原始数据
     * @param {number} requiredLength - 需要的长度
     * @returns {CryptoJS.lib.WordArray} - 调整后的数据
     */
    _adjustLength(data, requiredLength) {
        const dataBytes = data.words; // 获取数据的字节数组
        const dataLength = dataBytes.length * 4; // 计算数据的字节长度（每个 word 为 4 字节）

        if (dataLength > requiredLength) {
            // 如果数据长度超过要求，截断数据
            return CryptoJS.lib.WordArray.create(dataBytes.slice(0, requiredLength / 4));
        } else if (dataLength < requiredLength) {
            // 如果数据长度不足，填充数据
            const padding = new Array((requiredLength - dataLength) / 4).fill(0); // 填充 0
            return CryptoJS.lib.WordArray.create(dataBytes.concat(padding));
        } else {
            // 如果数据长度正好，直接返回
            return data;
        }
    }

    /**
     * DES 加密
     * @param {string} data - 需要加密的数据（字符串）
     * @returns {string} - 加密后的十六进制字符串
     */
    desEncrypt(data) {
        const encrypted = CryptoJS.DES.encrypt(
            CryptoJS.enc.Utf8.parse(data), // 将数据转换为 WordArray
            this.key,
            {
                iv: this.iv,
                mode: CryptoJS.mode.CFB, // CFB 模式
                padding: CryptoJS.pad.NoPadding,
            }
        );
        return encrypted.ciphertext.toString(CryptoJS.enc.Hex); // 返回十六进制格式的加密数据
    }

    /**
     * DES 解密
     * @param {string} data - 需要解密的十六进制字符串
     * @returns {string} - 解密后的原始数据（字符串）
     */
    desDecrypt(data) {
        const decrypted = CryptoJS.DES.decrypt(
            {
                ciphertext: CryptoJS.enc.Hex.parse(data), // 将十六进制字符串转换为 WordArray
            },
            this.key,
            {
                iv: this.iv,
                mode: CryptoJS.mode.CFB, // CFB 模式
                padding: CryptoJS.pad.NoPadding, // 无填充（与后端一致）
            }
        );
        return decrypted.toString(CryptoJS.enc.Utf8); // 返回 UTF-8 格式的原始数据
    }

    /**
     * AES 加密
     * @param {string} data - 需要加密的数据（字符串）
     * @returns {string} - 加密后的 Base64 字符串
     */
    aesEncrypt(data) {
        const encrypted = CryptoJS.AES.encrypt(
            CryptoJS.enc.Utf8.parse(data), // 将数据转换为 WordArray
            this.key,
            {
                iv: this.iv,
                mode: CryptoJS.mode.CBC, // CBC 模式
                padding: CryptoJS.pad.Pkcs7, // PKCS7 填充
            }
        );
        return encrypted.toString(); // 返回 Base64 格式的加密数据
    }

    /**
     * AES 解密
     * @param {string} data - 需要解密的 Base64 字符串
     * @returns {string} - 解密后的原始数据（字符串）
     */
    aesDecrypt(data) {
        const decrypted = CryptoJS.AES.decrypt(
            data,
            this.key,
            {
                iv: this.iv,
                mode: CryptoJS.mode.CBC, // CBC 模式
                padding: CryptoJS.pad.Pkcs7, // PKCS7 填充
            }
        );
        return decrypted.toString(CryptoJS.enc.Utf8); // 返回 UTF-8 格式的原始数据
    }
}

// 示例用法
const desCipher = new CryptoUtils('jiuwen', '12345678', 'DES'); // DES 加解密
const aesCipher = new CryptoUtils('jiuwen', '1234567890123456', 'AES'); // AES 加解密

export { desCipher, aesCipher };